Skip to content

Clamp colorbar axis domain to prevent inversion errors - #7908

Open
zeehio wants to merge 3 commits into
plotly:masterfrom
zeehio:claude/plotly-issue-6499-repro-6k2s7e
Open

Clamp colorbar axis domain to prevent inversion errors#7908
zeehio wants to merge 3 commits into
plotly:masterfrom
zeehio:claude/plotly-issue-6499-repro-6k2s7e

Conversation

@zeehio

@zeehio zeehio commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Fixes #6499 (axisDraw: Hitting ax.domain[1] < ax.domain[0]).

Claude assisted. I do understand the code though

Vertical colorbars could end up with ax.domain[1] < ax.domain[0], producing a negative axis length and throwing Something went wrong with axis scaling during draw. This happened in src/components/colorbar/draw.js in two places:

  1. The initial domain assignment, when the colorbar's available height (len * plot height) is smaller than 2 * ypad. This is the one actually hit by the real-world report in the issue (a plot with two legends/guides squeezing the colorbar's available space) — it fires before any title logic even runs.
  2. The title-height adjustment, when the colorbar title (top or bottom side) is taller than the colorbar's domain. The issue's original report/suggested fix only covered the top-side branch; the symmetric bottom/right-side branch had the identical bug and is fixed here too.

All three domain assignments are now clamped with Math.max/Math.min so domain[1] can never drop below domain[0] (or vice versa), instead of throwing. In the extreme-squeeze case the colorbar collapses to zero height rather than crashing — a defensive fix, not a full relayout, but it eliminates the exception.

Repro/verification notes (from investigating the issue): the crash reproduces end-to-end via ggplot2ggplotly() → plotly.js when a colorbar's available space is tight relative to its title/padding, confirmed with a real htmlwidgets::saveWidget() output rendered in headless Chromium at short container heights (≲80px) — consistent with the issue's note that reproduction depends on the window size. It also depends on the legend size.

Added 3 regression tests to test/jasmine/tests/colorbar_test.js, one per fixed code path — verified each fails with the exact reported error on the pre-fix code and passes after the fix.

claude added 2 commits July 16, 2026 17:40
Vertical colorbars could end up with ax.domain[1] < ax.domain[0],
producing a negative axis length and throwing "Something went wrong
with axis scaling" during draw. This happened in two spots:

- the initial domain assignment, when the colorbar's available height
  (len * plot height) is smaller than 2 * ypad
- the title-height adjustment, when the title (top or bottom side) is
  taller than the colorbar's domain

All three assignments are now clamped so domain[1] can never drop
below domain[0] (or domain[0] rise above domain[1]).

Fixes plotly#6499

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011XRrkTKVes3TEaB8FNDrea
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011XRrkTKVes3TEaB8FNDrea
@zeehio
zeehio force-pushed the claude/plotly-issue-6499-repro-6k2s7e branch from 8e526a4 to 4d427c7 Compare July 16, 2026 17:55
@zeehio
zeehio marked this pull request as ready for review July 16, 2026 17:56
@camdecoster camdecoster self-assigned this Jul 28, 2026
@camdecoster

Copy link
Copy Markdown
Contributor

Thanks for the PR! Closing the loop on the issue after 3 years is pretty cool. I'll review and follow up with you.

@camdecoster camdecoster left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good! I believe there's one more line to update.

Comment thread src/components/colorbar/draw.js Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this line will need to be updated as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! Thanks!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of creating helper functions to handle this and using those on each affected line? Something like this:

const insetDomainStart = (domain, delta) => [Math.min(domain[0] + delta, domain[1]), domain[1]];
const insetDomainEnd = (domain, delta) => [domain[0], Math.max(domain[1] - delta, domain[0])];

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Factor the repeated "clamp domain endpoint without crossing the
other bound" logic into two small helpers, insetDomainStart and
insetDomainEnd, and use them at all four call sites instead of
inline Math.max/Math.min.

This also fixes a spot the review caught that the original patch
missed: the horizontal colorbar's title.side === 'right' branch
had the same unclamped-domain bug as the vertical title branches,
just never hit by the reported repro. Added a regression test for
it alongside the existing three.

AI-assistant: Claude Sonnet 5 <noreply@anthropic.com>
@zeehio

zeehio commented Jul 31, 2026

Copy link
Copy Markdown
Contributor Author

All is done, thank you for the review!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

axisDraw: Hitting ax.domain[1] < ax.domain[0]

3 participants